﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geoprocessor;
using ESRI.ArcGIS.Geoprocessing;
using ESRI.ArcGIS.DataManagementTools;
using System.IO;
using ESRI.ArcGIS.SpatialAnalystTools;

namespace PlanningGIS.ArcGIS
{
    /// <summary>
    /// GP处理类。
    /// 通过返回结果得到执行是否成功；通过OutMessage、或GetMessage得到执行的消息
    /// </summary>
    [ComVisible(true)]
    public static class GeoprocessorHelper
    {
        #region 执行GP
        /// <summary>
        /// 获取GP输出的消息
        /// </summary>
        public static List<string> OutMessage { get; private set; }

        /// <summary>
        /// 获取GP输出的消息
        /// </summary>
        /// <returns></returns>
        public static string GetMessage()
        {
            if (OutMessage == null || OutMessage.Count == 0) return "";
            string msg = "";
            foreach (string s in OutMessage)
            {
                msg += s + ";";
            }
            return msg;
        }

        /// <summary>
        /// 执行GP操作
        /// </summary>
        /// <param name="process">要处理的GP对象</param>
        /// <returns></returns>
        public static bool Execute(IGPProcess process)
        {
            Geoprocessor geoprocessor = new Geoprocessor();
            return Execute(process, geoprocessor);
        }

        /// <summary>
        /// 执行GP操作
        /// </summary>
        /// <param name="process">要处理的GP对象</param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static bool Execute(IGPProcess process, out string msg)
        {
            bool suc = Execute(process);
            msg = GetMessage();
            return suc;
        }

        /// <summary>
        /// 执行GP操作
        /// </summary>
        /// <param name="process">要处理的GP对象</param>
        /// <param name="geoprocessor">Gp对象</param>
        /// <returns></returns>
        public static bool Execute(IGPProcess process , Geoprocessor geoprocessor)
        {
            geoprocessor.OverwriteOutput = true;
            bool success = false;
            try
            {
                IGeoProcessorResult results = (IGeoProcessorResult)geoprocessor.Execute(process, null);
                if (results == null || results.Status != esriJobStatus.esriJobSucceeded)
                    success = false;
                else
                    success = true;
                ReturnMessage(geoprocessor);
                GC.Collect();
                return success;
            }
            catch (Exception ex)
            {
                ReturnMessage(geoprocessor);
                OutMessage.Add(ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 执行GP操作
        /// </summary>
        /// <param name="process">要处理的GP对象</param>
        /// <param name="geoprocessor">Gp对象</param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static bool Execute(IGPProcess process, Geoprocessor geoprocessor,out string msg)
        {
            bool suc = Execute(process, geoprocessor);
            msg = GetMessage();
            return suc;
        }

        /// <summary>
        /// 执行地理处理工具。
        /// </summary>
        /// <param name="name">地理处理工具。</param>
        /// <param name="parameters">相关参数。</param>
        /// <returns>执行结果，如果执行成功则返回 true</returns>
        public static bool Execute(string name, IVariantArray parameters)
        {
            Geoprocessor gp = new Geoprocessor();
            gp.OverwriteOutput = true;
            bool success = false;
            try
            {
                IGeoProcessorResult results = (IGeoProcessorResult)gp.Execute(name, parameters, null);
                if (results == null || results.Status != esriJobStatus.esriJobSucceeded)
                    success = false;
                else
                    success = true;
                ReturnMessage(gp);
                GC.Collect();
                return success;
            }
            catch (Exception ex)
            {
                ReturnMessage(gp);
                OutMessage.Add(ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 执行自定义脚本工具。
        /// </summary>
        /// <param name="scriptFilePath">脚本文件路径。</param>
        /// <param name="toolName">工具名称。</param>
        /// <param name="parameters">相关参数。</param>
        /// <returns>执行结果，如果执行成功则返回 true</returns>
        public static bool Execute(string scriptFilePath, string toolName, IVariantArray parameters)
        {
            bool success = false;
            if (!File.Exists(scriptFilePath))
            {
                OutMessage.Add("脚本文件不存在。");
                return success;
            }
            Geoprocessor gp = new Geoprocessor();
            gp.AddToolbox(scriptFilePath);
            gp.OverwriteOutput = true;
            try
            {
                IGeoProcessorResult results = (IGeoProcessorResult)gp.Execute(toolName, parameters, null);
                if (results == null || results.Status != esriJobStatus.esriJobSucceeded)
                    success = false;
                else
                    success = true;
                ReturnMessage(gp);
                GC.Collect();
                return success;
            }
            catch (Exception ex)
            {
                ReturnMessage(gp);
                OutMessage.Add(ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 返回执行的消息
        /// </summary>
        /// <param name="geoprocessor"></param>
        /// <returns></returns>
        private static void ReturnMessage(Geoprocessor geoprocessor)
        {
            OutMessage = new List<string>();
            for (int i = 0; i < geoprocessor.MessageCount; i++)
            {
                //if (geoprocessor.GetReturnCode(i) != 0)
                {
                    OutMessage.Add(geoprocessor.GetMessage(i));
                }
            }
        }
        
        #endregion

        /// <summary>
        /// 该函数用于从一个层到另一个层数据的拷贝
        /// </summary>
        /// <param name="inFeatclass">输入要素类</param>
        /// <param name="outFeatclass">输出要素类</param>
        public static bool Copy2FeatureClass(IFeatureClass inFeatclass, IFeatureClass outFeatclass)
        {
            if (inFeatclass == null || outFeatclass == null) return false;
            Copy pCopy = new Copy(inFeatclass, outFeatclass);
            return Execute(pCopy);
        }

        /// <summary>
        /// 该函数是从一个要素类追加到另外一个要素类上
        /// </summary>
        /// <param name="inFeatclass">输入要素类</param>
        /// <param name="outFeatclass">输出要素类</param>
        /// <returns></returns>
        public static bool ApendFeatureClass(IFeatureClass inFeatclass, IFeatureClass outFeatclass)
        {
            if (inFeatclass == null || outFeatclass == null) return false;
            Append pAppend = new Append(inFeatclass, outFeatclass);
            return Execute(pAppend);
        }

        /// <summary>
        /// 调用GP工具进行地理对象拓扑检查
        /// </summary>
        /// <param name="inFeatureClass">要检查的要素类</param>
        /// <param name="out_table">输出的结果全路径，如C:\Db.gdb\outname</param>
        /// <returns></returns>
        public static bool CheckGeometry(object inFeatureClass, string out_table)
        {
            if (inFeatureClass == null) return false;
            CheckGeometry checkGeometry = new CheckGeometry();
            checkGeometry.in_features = inFeatureClass;
            checkGeometry.out_table = out_table;
            return Execute(checkGeometry);
        }

        /// <summary>
        /// CAD 导出。
        /// </summary>
        /// <param name="input">输入（要素类地址）。</param>
        /// <param name="output">输出（CAD 文件存储路径）</param>
        /// <returns></returns>
        public static bool ExportCad(string input, string output)
        {
            IVariantArray parameters = new VarArray();
            parameters.Add(input);
            parameters.Add(string.Format("ACAD,{0},\"RUNTIME_MACROS,\"\"DEFAULT_ATTR_STORAGE,insert_attributes,VERSION,Release2007,TEMPLATEFILE_GUI,\"\",META_MACROS,\"\"DestDEFAULT_ATTR_STORAGE,insert_attributes,DestVERSION,Release2007,DestTEMPLATEFILE_GUI,\"\",METAFILE,ACAD,COORDSYS,\"", output));
            return GeoprocessorHelper.Execute("QuickExport", parameters);
        }

        /// <summary>
        /// 栅格计算器
        /// </summary>
        /// <param name="rasters"></param>
        /// <param name="express"></param>
        /// <param name="out_raster"></param>
        /// <returns></returns>
        public static string RasterCalcutor(string where, string out_raster)
        {
            RasterCalculator rc = new RasterCalculator();  //
            rc.output_raster = out_raster;
            rc.expression = where;
            string msg = "";
            if (!GeoprocessorHelper.Execute(rc, out msg))
            {
                //LogHelper.WriteErrLog("栅格计算操作失败" + msg + "\r\n");
                return msg;
            }
            return "";

        }

        /// <summary>
        /// 从一个工作空间复制一个要素类到另一个工作空间
        /// </summary>
        /// <param name="featureclassname">要复制的要素类名称</param>
        /// <param name="fromworkspace">源工作空间</param>
        /// <param name="toworkspace">目标工作空间</param>
        /// <returns></returns>
        public static bool CopyFeatureClass(string featureclassname, IWorkspace fromworkspace, IWorkspace toworkspace)
        {
            string in_user = "";
            string in_data = GetPathName(fromworkspace, out in_user);
            if (!string.IsNullOrWhiteSpace(in_user))
                in_data += "\\" + in_user + ".";
            string out_user = "";
            string out_data = GetPathName(toworkspace, out out_user);
            if (!string.IsNullOrWhiteSpace(out_user))
                out_data += "\\" + out_user + ".";
            //IFeatureClass featCls = GeodatabaseHelper.OpenFeatureClass(fromworkspace, featureclassname);
            //if (featCls.FeatureDataset != null)
            //    fullname = fromworkspace.PathName + "\\" + featCls.FeatureDataset.BrowseName + "\\" + featureclassname;
            return CopyFeatureClass(featureclassname, in_data, out_data);
        }
        
        /// <summary>
        /// 从一个工作空间复制一个要素类到另一个工作空间
        /// </summary>
        /// <param name="featureclassname">要复制的要素类名称</param>
        /// <param name="fromworkspace">源工作空间</param>
        /// <param name="toworkspace">目标工作空间</param>
        /// <returns></returns>
        public static bool CopyFeatureClass(string featureclassname, string fromworkspace, string toworkspace)
        {
            string in_data = fromworkspace + "\\" + featureclassname;
            if (fromworkspace.EndsWith(".") || fromworkspace.EndsWith("\\"))
                in_data = fromworkspace + featureclassname;
            string out_data = toworkspace + "\\" + featureclassname;
            if (toworkspace.EndsWith(".") || toworkspace.EndsWith("\\"))
                out_data = toworkspace + featureclassname;
            Copy copy = new Copy();
            copy.data_type = "FeatureClass";
            copy.in_data = in_data;
            copy.out_data = out_data;
            return Execute(copy);
        }

        /// <summary>
        /// 从一个工作空间复制一个数据集到另一个工作空间
        /// </summary>
        /// <param name="datasetname"></param>
        /// <param name="fromworkspace"></param>
        /// <param name="toworkspace"></param>
        /// <returns></returns>
        public static bool CopyFeatureDataSet(string datasetname, IWorkspace fromworkspace, IWorkspace toworkspace)
        {
            string in_user = "";
            string in_data = GetPathName(fromworkspace, out in_user);
            if (!string.IsNullOrWhiteSpace(in_user))
                in_data += "\\" + in_user + ".";
            string out_user = "";
            string out_data = GetPathName(toworkspace, out out_user);
            if (!string.IsNullOrWhiteSpace(out_user))
                out_data += "\\" + out_user + ".";
            return CopyFeatureDataSet(datasetname, in_data, out_data);
        }

        /// <summary>
        /// 从一个工作空间复制一个数据集到另一个工作空间
        /// </summary>
        /// <param name="datasetname"></param>
        /// <param name="fromworkspace"></param>
        /// <param name="toworkspace"></param>
        /// <returns></returns>
        public static bool CopyFeatureDataSet(string datasetname, string fromworkspace, string toworkspace)
        {
            string in_data = fromworkspace + "\\" + datasetname;
            if (fromworkspace.EndsWith(".") || fromworkspace.EndsWith("\\"))
                in_data = fromworkspace + datasetname;
            string out_data = toworkspace + "\\" + datasetname;
            if (toworkspace.EndsWith(".") || toworkspace.EndsWith("\\"))
                out_data = toworkspace + datasetname;
            Copy copy = new Copy();
            copy.data_type = "FeatureDataset";
            copy.in_data = in_data;
            copy.out_data = out_data;
            return Execute(copy);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="workspace"></param>
        /// <param name="username"></param>
        /// <returns></returns>
        private static string GetPathName(IWorkspace workspace, out string username)
        {
            username = "";
            if (!string.IsNullOrWhiteSpace(workspace.PathName))
                return workspace.PathName + "\\";
            string sdename = WorkspaceHelper.GetPropertyDefaultName(workspace.ConnectionProperties);
            WorkspaceHelper.SavePropertySet(workspace.ConnectionProperties, sdename);
            username = workspace.ConnectionProperties.GetProperty("User").ToString();
            return sdename;
        }
    }
}
